import json
import logging
import re

from django import http
from django.conf import settings
from django.contrib.auth import login, authenticate, logout
from django.shortcuts import render, redirect
from django.views import View

from celery_tasks.emails.tasks import send_verify_email
from utils.views import LoginRequiredJSONMixin
from . import constants
from .models import User, Address
from django.urls import reverse
from utils.response_code import RETCODE
from django_redis import get_redis_connection
from django.contrib.auth.mixins import LoginRequiredMixin

from .utils import generate_verify_email_url, check_verify_email_url

logger = logging.getLogger("django")


# Create your views here.

class RegisterView(View):
    # 用户注册
    def get(self, request):
        # 注册页面
        return render(request, 'register.html')

    def post(self, request):
        """ 用户注册逻辑 """

        # 接收数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        sms_code_client = request.POST.get('sms_code')

        # 判断参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        # 判断两次密码是否一致
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选用户协议')

        redis_connection = get_redis_connection("Verifications")
        sms_code_server = redis_connection.get(f"sms_code{mobile}").decode()
        if not sms_code_server:
            return render(request, 'register.html', {'sms_code_errmsg': '短信验证码失效'})

        if sms_code_server != sms_code_client:
            return render(request, 'register.html', {'sms_code_errmsg': '短信验证码错误'})

        # 保存数据
        # 保存注册数据
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
            # 用户登录
            login(request, user)
        except Exception as e:

            return render(request, 'register.html', {'register_errmsg': '注册失败' + e})

        # 响应注册结果
        # return http.HttpResponse('注册成功，重定向到首页')
        # 返回数据
        # 写入 将 username 写入到 cookie
        response = redirect(reverse("contents:index"))
        response.set_cookie("username", user.username, max_age=3600 * 24 * 15)  # 15 天
        return response


class LoginView(View):
    """用户登录"""

    def get(self, request):
        """用户登录页面"""

        return render(request, 'login.html')

    def post(self, request):
        """"用户登录页面 逻辑处理"""
        # 接收数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        remember = request.POST.get('remember')
        if not all([username, password]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入正确的用户名或手机号')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('密码最少8位，最长20位')

        # 认证用户 使用账号查询用户是否存在，如果用户存在，再校验密码是否正确 后期多用户 优化
        user = authenticate(username=username, password=password)

        if user is None:
            return render(request, 'login.html', {'account_errmsg': '账号或密码错误'})

        # 状态保持
        login(request, user)
        # 确定状态保持 时间

        if remember != "on":
            # 没有状态保持 浏览器会话结束后销毁 单位是秒
            request.session.set_expiry(0)
        else:
            # 保存周期 2周 默认 2 周
            request.session.set_expiry(None)

        # 取出重定向数据
        redirect_to = request.GET.get('redirect_to')
        if redirect_to:
            # 重定向到 redirect_to
            response = redirect(redirect_to)
        else:
            response = redirect(reverse("contents:index"))

        # 写入 将 username 写入到 cookie
        response.set_cookie("username", user.username, max_age=3600 * 24 * 15)  # 15 天

        return response


class LogoutView(View):
    """退出登录"""

    def get(self, request):
        logout(request)
        response = redirect(reverse("contents:index"))
        # 清除username cookie
        response.delete_cookie("username")
        return response


class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        """
        :param request:
        :param username:  用户名
        :return: json
        """
        # 接收校验参数
        # 主题业务逻辑
        count = User.objects.filter(username=username).count()
        return http.JsonResponse(
            {
                "code": RETCODE.OK, "errmsg": "ok", "count": count
            }
        )

        # 返回数据
        pass


class UserCenterView(LoginRequiredMixin, View):
    """用户中心"""
    login_url = "/user/login/"
    redirect_field_name = "redirect_to"  # 默认 next

    def get(self, request):
        # 如果登录就直接进入用户中心  没有登录进入 登录界面 登陆成功后 进入用户中心 后期使用 LoginRequiredMixin优化
        # if request.user.is_authenticated:
        #     return render(request, "user_center_info.html")
        # else:
        #     return  redirect(reverse("users:login·"))

        # 如果 用户已经登录 则 request.user 里面就是用户对象

        content = {
            "username": request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_active
        }
        return render(request, "user_center_info.html", content)


class EmailView(LoginRequiredJSONMixin,View):
    """添加邮箱"""
    login_url = "/user/login/"
    redirect_field_name = "redirect_to"  # 默认 next
    def put(self, request):
        # 获取数据
        json_str = request.body.decode('utf-8')
        json_dict = json.loads(json_str)
        email = json_dict["email"]

        # 校验参数
        # 判断 是否为邮箱
        if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',email):
            return http.HttpResponseForbidden("参数email 有误")

        # 保存email 数据
        try:
            user = request.user
            user.email = email
            user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({
                "code": RETCODE.DBERR,
                "msg": "添加邮箱失败"
            })
        print(settings.EMAIL_FROM)
        # 发送邮件验证
        verify_url= generate_verify_email_url(user)
        send_verify_email.delay("15082411714@163.com",verify_url)

        # 响应结果

        return http.JsonResponse({
            "code": RETCODE.OK,
            "msg": "添加邮箱成功"
        })


class VerifEmailView(View):
    def get(self,request):
        # 接受参数
        token = request.GET.get("token")
        # 校验参数
        if not token:
            http.HttpResponseForbidden("缺少token")


        # 根据token 的用户信息获取到user对象 修改激活字段
        user = check_verify_email_url(token)
        if user is None:
            return http.HttpResponseForbidden("无效的token")

        # 修改激活字段
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return  http.HttpResponseServerError("激活邮箱失败")

        # 重定向 到用户中心
        return redirect(reverse("users:usercenter"))


class AddressView(LoginRequiredMixin,View):
    """用户收货地址"""
    def get(self,request):
        return render(request,"user_center_site.html")



# 新增收获地址
class CreateAddressView(LoginRequiredJSONMixin,View):
    """新增收获地址"""
    def post(self,request):
        # 接收参数
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # 业务处理：保存地址信息
                # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            # 设置默认地址 如果没有默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        # 新增地址成功，将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})